﻿using System;
using System.Text.RegularExpressions;
using Phoenix.Diagnostics;
using Xunit;

namespace Phoenix.Tests.Diagnostics
{
    public class TraceTests
    {
        public TraceTests()
        {
            Trace.Appenders.Clear();
        }

        [Fact]
        public void debug_trace_should_not_log_when_level_is_info()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Info;

            // act
            Trace.WriteDebug(this, ()=>"Test");

            // assert
            Assert.False(traced);
        }

        [Fact]
        public void debug_trace_should_log_when_level_is_debug()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Debug;

            // act
            Trace.WriteDebug(this, () => "Test");

            // assert
            Assert.True(traced);
        }

        [Fact]
        public void info_trace_should_not_log_when_level_is_warning()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Warning;

            // act
            Trace.WriteInfo(this, () => "Test");

            // assert
            Assert.False(traced);
        }

        [Fact]
        public void info_trace_should_log_when_level_is_info()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Debug;

            // act
            Trace.WriteInfo(this, () => "Test");

            // assert
            Assert.True(traced);
        }

        [Fact]
        public void warning_trace_should_not_log_when_level_is_error()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Error;

            // act
            Trace.WriteWarning(this, () => "Test");

            // assert
            Assert.False(traced);
        }

        [Fact]
        public void warning_trace_should_log_when_level_is_warning()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Warning;

            // act
            Trace.WriteWarning(this, () => "Test");

            // assert
            Assert.True(traced);
        }

        [Fact]
        public void error_trace_should_log_when_level_is_error()
        {
            // arrange
            var traced = false;
            Trace.Appenders.Add(s => traced = true);
            Trace.TraceLevel = TraceLevel.Error;

            // act
            Trace.WriteError(this, () => "Test");

            // assert
            Assert.True(traced);
        }

        [Fact]
        public void trace_scope_with_child_writes_scopes_children()
        {
            // arrange
            Trace.TraceLevel = TraceLevel.Debug;
            Trace.TraceStringFormat = "{5}";
            const string regexPattern = @"test\r\n\{\s+?childLog\r\n\} \d+ms";
            var traceValue = string.Empty;
            Trace.Appenders.Add(s => traceValue+=s+"\r\n");

            // act
            var scope = TraceScope.Create(this, TraceLevel.Info, () => "test");
            Trace.WriteInfo(this, ()=>"childLog");
            scope.Dispose();

            // assert
            Assert.True(Regex.Match(traceValue, regexPattern).Success, string.Format("{0} did not match expression {1}", traceValue, regexPattern));
        }

        [Fact]
        public void trace_scope_with_no_child_writes_should_be_on_a_single_line()
        {
            // arrange
            Trace.TraceLevel = TraceLevel.Debug;
            Trace.TraceStringFormat = "{5}";
            const string regexPattern = @"test... \d+ms";
            string traceValue = null;
            Trace.Appenders.Add(s => traceValue = s);

            // act
            TraceScope.Create(this, TraceLevel.Info, () => "test").Dispose();

            // assert
            Assert.True(Regex.Match(traceValue, regexPattern).Success, string.Format("{0} did not match expression {1}", traceValue, regexPattern));
        }

        [Fact]
        public void child_trace_scope_is_nested()
        {
            // arrange
            Trace.TraceLevel = TraceLevel.Debug;
            Trace.TraceStringFormat = "{5}";
            const string regexPattern = @"test\r\n\{\s+?childScope... \d+ms\r\n\} \d+ms";
            var traceValue = string.Empty;
            Trace.Appenders.Add(s => traceValue += s + "\r\n");

            // act
            var scope = TraceScope.Create(this, TraceLevel.Info, () => "test");
            TraceScope.Create(this, TraceLevel.Info, () => "childScope").Dispose();
            scope.Dispose();

            // assert
            Assert.True(Regex.Match(traceValue, regexPattern).Success, string.Format("{0} did not match expression {1}", traceValue, regexPattern));
        }
    }
}